#include "Source.h"
#include <iostream>

using namespace AgoraClient;

Source::Source(ALenum format, ALsizei freq, bool run) :
_run(run),
_format(format),
_freq(freq)
{
	alGenSources(1, &this->_source);
}

Source::~Source()
{
	alDeleteSources(1, &this->_source);
	this->Clear();
}

bool Source::IsRunning()
{
	return _run;
}

void Source::AddSamples(void *samples, unsigned int size)
{
	ALuint buffer;
	ALint	processed;

	alGetSourcei(this->_source, AL_BUFFERS_PROCESSED, &processed);
	while (processed-- > 0)
	{
		alSourceUnqueueBuffers(this->_source, 1, &buffer);
		this->_freeALBuf.push_back(buffer);
		this->_usedALBuf.remove(buffer);

	}
	if (!this->_freeALBuf.size())
	{
		alGenBuffers(1, &buffer);
		alBufferData(buffer, this->_format, samples, size, this->_freq);
		alSourceQueueBuffers(this->_source, 1, &buffer);
		this->_usedALBuf.push_back(buffer);
	}
	else
	{
		alBufferData(this->_freeALBuf.back(), this->_format, samples, size, this->_freq);
		alSourceQueueBuffers(this->_source, 1, &this->_freeALBuf.back());
		this->_usedALBuf.push_back(this->_freeALBuf.back());
		this->_freeALBuf.pop_back();
	}
	if (this->_run && !this->checkRun())
	{
		alSourcePlay(this->_source);
	}
}

bool Source::checkRun()
{
	ALenum state;

	alGetSourcei(this->_source, AL_SOURCE_STATE, &state);
	return (state == AL_PLAYING);
}

void Source::SetPosition()
{
}

void Source::SetMaxBuffer()
{
}

void Source::SetFormat(ALenum format)
{
	this->_format = format;
}

void Source::SetFrequence(ALsizei freq)
{
	this->_freq = freq;
}

int Source::GetFormat()
{
	return this->_format;
}

int Source::GetFrequence()
{
	return this->_freq;
}


void Source::Start()
{
	this->_run = true;
}

void Source::Stop()
{
	this->_run = false;
	alSourceStop(this->_source);
}

void Source::Clear()
{
	ALuint *buffers = 0;

	alSourceUnqueueBuffers(this->_source, this->_usedALBuf.size(), buffers);
	std::list<ALuint>::iterator it = this->_usedALBuf.begin();
	std::list<ALuint>::iterator end = this->_usedALBuf.end();
	for(; it != end; ++it)
	{
		alDeleteBuffers(1, &(*it));
	}
	std::list<ALuint>::iterator it2 = this->_freeALBuf.begin();
	std::list<ALuint>::iterator end2 = this->_freeALBuf.end();
	for(; it != end; ++it)
	{
		alDeleteBuffers(1, &(*it));
	}
	this->_freeALBuf.clear();
	this->_usedALBuf.clear();
}

void Source::SetSpacialInfo(int x, int y, int z, 
							 int velocityX, int velocityY, int velocityZ,
							 int dirX, int dirY, int dirZ)
{
	alSource3i(this->_source, AL_POSITION, x, y, z);
	alSource3i(this->_source, AL_VELOCITY, velocityX, velocityY, velocityZ);
	alSource3i(this->_source, AL_DIRECTION, dirX, dirY, dirZ);
}